package org.gpp.proj1.ui.gui.jme;

import java.io.FileNotFoundException;

import org.gpp.proj1.bone.parser.BoneStructureParser;
import org.gpp.proj1.bone.parser.BoneStructureParserException;
import org.gpp.proj1.logic.metadata.PartEntry;
import org.gpp.proj1.logic.metadata.RobotEntry;
import org.gpp.proj1.logic.metadata.RobotPartCategory;
import org.gpp.proj1.robot.Robot;
import org.gpp.proj1.robot.RobotImpl;
import org.gpp.proj1.robot.part.SparePart;
import org.gpp.proj1.robot.part.parser.InvalidPartFileException;
import org.gpp.proj1.robot.part.parser.PartFileParser;

import com.jme.input.InputHandler;
import com.jme.light.DirectionalLight;
import com.jme.math.FastMath;
import com.jme.math.Quaternion;
import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.scene.state.LightState;
import com.jme.system.DisplaySystem;
import com.jme.util.LoggingSystem;
import com.jmex.awt.SimpleCanvasImpl;

public class RobotDisplayJMECanvas extends SimpleCanvasImpl {

	private static final float ROBOT_HEIGHT_OFFSET = -6.5f;

	private static final String DEFAULT_ANIMATION = "stopped";
	
	private Quaternion rotQuat;
	private float angle = 0;
	private Vector3f axis;
	private InputHandler input;

	private Robot robot;
	private LightState lightState;
	private RobotEntry currentRobotEntry;

	public RobotDisplayJMECanvas(RobotEntry robotEntry, int width, int height) {
		super(width, height);
		
		this.currentRobotEntry = robotEntry;
	}

	public void setRobotParts(RobotEntry robotEntry) {
		
		this.setPart( RobotPartCategory.LEGS, robotEntry );
		this.setPart( RobotPartCategory.TORSO, robotEntry );		
		this.setPart( RobotPartCategory.ARM_LEFT, robotEntry );
		this.setPart( RobotPartCategory.ARM_RIGHT, robotEntry );
		this.setPart( RobotPartCategory.HEAD, robotEntry );
	}
	
	public void changePart(RobotPartCategory category, PartEntry entry) {
		
		this.setPart( category, entry );
	}

	private void setPart(RobotPartCategory category, RobotEntry entry) {
		PartEntry partEntry = entry.getPart( category );
		
		if( partEntry == null ) {
			LoggingSystem.getLogger().warning( "Part for category \"" + category + "\" not found" );
			return;
		}
		
		this.setPart( category , partEntry );
	}
	
	private void setPart(RobotPartCategory category, PartEntry partEntry) {
		try {
			SparePart part = PartFileParser.parseFile( partEntry.getFile() );	
			this.robot.setPart( category.getPartTag(), part );
			this.robot.getNode().updateRenderState();
		} catch (FileNotFoundException e) {
			LoggingSystem.getLogger().warning( "Could not load file: File not found" );
			LoggingSystem.getLogger().throwing( this.getClass().getName(), "setPart()", e );
		} catch (InvalidPartFileException e) {
			LoggingSystem.getLogger().warning( "Could not load file: Invalid file" );
			LoggingSystem.getLogger().throwing( this.getClass().getName(), "setPart()", e );
		}
	}

	public void simpleSetup() {
		// Normal Scene setup stuff...
		rotQuat = new Quaternion();
		axis = new Vector3f(0, 0.5f, 0);
		axis.normalizeLocal();

		input = new InputHandler();
		
		BoneStructureParser parser = new BoneStructureParser( "res/bone/humanoid.bon" );
		try {
			robot = new RobotImpl( parser.getBoneStructure() );

			if( currentRobotEntry != null ) {
				this.setRobotParts( currentRobotEntry );
			}

			robot.getNode().setLocalTranslation( new Vector3f( 0, ROBOT_HEIGHT_OFFSET, 0 ) );
			robot.getNode().updateGeometricState( 0, true );
			
			robot.setAnimation( DEFAULT_ANIMATION );
			
			this.rootNode.attachChild( robot.getNode() );
		} catch (BoneStructureParserException e) {
			LoggingSystem.getLogger().warning( "Could not load robot" );
			LoggingSystem.getLogger().throwing( this.getClass().getName(), "<init>", e );
		}
		
		this.lightState = DisplaySystem.getDisplaySystem().getRenderer().createLightState();
		DirectionalLight light = new DirectionalLight();
		light.setDirection( new Vector3f( 0.4f, -1.0f, 0.4f ) );
		light.setAmbient( ColorRGBA.white );
		light.setDiffuse( ColorRGBA.white );
		light.setEnabled( true );
		this.lightState.attach( light );

		rootNode.setRenderState( lightState );
		rootNode.updateGeometricState(0, true);
		rootNode.updateRenderState();
	}

	public void simpleUpdate() {
		input.update( tpf );

		if (tpf < 1) {
			angle = angle + (tpf * 25);
			if (angle > 360) {
				angle = 0;
			}
		}
		rotQuat.fromAngleNormalAxis(angle * FastMath.DEG_TO_RAD, axis);
		robot.getNode().setLocalRotation(rotQuat);
	}
}